#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2023/8/6 11:44
# @Author  : huidong.bai
# @File    : TestCaseParser.py
# @Software: PyCharm
# @Mail    : MasterBai2018@outlook.com
import pdb
import re
import copy
import pandas as pd
from src.utils.common import is_available_file
from conf.MongoConfig import typeMapple
from src.utils.AutoChangeText import AutoChangeText


class Property:
    def __init__(self, name, matches, value):
        self.name = name
        self.matches = matches
        self.value = value


class TestCaseHeader:
    def __init__(self, channel, msgType, caseParam, absTime, carType, caseBref, delayTolerance, faPassRate, frPassRate, timeBoundaryTolerance, cpuMemTag, device_name):
        self.channel = Property("channel", channel, None)
        self.msgType = Property("msgType", msgType, None)
        self.caseParam = Property("caseParam", caseParam, None)
        self.absTime = Property("absTime", absTime, None)
        self.carType = Property("carType", carType, None)
        self.caseBref = Property("caseBref", caseBref, None)
        self.delayTolerance = Property("delayTolerance", delayTolerance, None)
        self.faPassRate = Property("faPassRate", faPassRate, None)
        self.frPassRate = Property("frPassRate", frPassRate, None)
        self.timeBoundaryTolerance = Property("timeBoundaryTolerance", timeBoundaryTolerance, None)
        self.cpuMemTag = Property("cpuMenTag", cpuMemTag, None)
        self.device_name = Property("device_name", device_name, None)

def check_line_filter(tag):
    s_tag = 1
    e_tag = 40000
    if not tag:
        return s_tag, e_tag
    try:
        start, end = [i.strip() for i in tag.split("-")]
        if len(start) == 0 or len(end) == 0:
            raise ValueError("Case Filter参数传入错误: {tag}, 请输入正确的-F参数")
        if start == "*":
            s_tag = 1
            e_tag = int(end)
            if e_tag <= 0:
                raise ValueError("Case Filter参数传入错误: {tag}, end tag不能小于0, 请输入正确的-F参数")
        elif end == "*":
            s_tag = int(start)
            e_tag = 40000
            if s_tag <= 0:
                raise ValueError("Case Filter参数传入错误: {tag}, start tag不能小于0, 请输入正确的-F参数")
        elif start == "*" and end == "*":
            raise ValueError("Case Filter参数传入错误: {tag}, 请输入正确的-F参数")

        else:
            s_tag = int(start)
            e_tag = int(end)
            if s_tag <= 0 or e_tag <= 0 or e_tag < s_tag:
                raise ValueError(f"Case Filter参数传入错误: {tag}, 请输入正确的-F参数")

        return int(s_tag), int(e_tag)
    except Exception as e:
        raise e


class TestCaseParser:
    case_header = TestCaseHeader(
        channel="DEFAULT_CHANNEL",
        msgType="DEFAULT_MSGTYPE",
        caseParam="DEFAULT_PARAM",
        absTime="DEFAULT_ABSTIME",
        carType="DEFAULT_CARTYPE",
        caseBref="CASE_BREF",
        delayTolerance="DELAY_TOLERANCE",
        faPassRate="FA_PASS_RATE",
        frPassRate="FR_PASS_RATE",
        timeBoundaryTolerance="TIME_BOUNDARY_TOLERANCE",
        cpuMemTag="CPU_MEM_TAG",
        device_name="DEFAULT_DEVICENAME",
    )
    caseList = []

    def __init__(self, case_path):
        self.case_path = case_path
        self.__parse_header()

    def __parse_header(self):
        if not is_available_file(self.case_path):
            raise Exception(f'没有找到Case文件,请检查: {self.case_path}')

        if ".xlsx" in self.case_path or '.xls' in self.case_path:
            return

        with open(self.case_path, 'r', encoding='utf-8') as fp:
            for line in fp:
                line = line.strip()
                for i in self.case_header.__dict__.keys():
                    if line.startswith("@" + self.case_header.__getattribute__(i).matches):
                        self.case_header.__getattribute__(i).value = line.split("#")[0].split(":")[1].strip()

    def get_case_list(self, tag):
        if '.xlsx' in self.case_path or '.xls' in self.case_path:
            return self.__read_excel_case(tag)
        else:
            case_result = self.__read_case(tag)
            # 在内存中进行修改audio_text的输入，替换audio_text为voice
            # 设置临时变量存储audio_text的数据
            temp_case_list = []
            for case in case_result:
                if re.search("audioText:", case['INPUT']):
                    temp_case_list.append(case)
            # 导入生成音频模块
            if len(temp_case_list) > 0:
                auto_class = AutoChangeText(temp_case_list)
                auto_class.parse_pannel()
            return case_result

    def __read_excel_case(self, tag=None):
        df = pd.read_excel(self.case_path)
        df = df.fillna(value='None')
        columns = df.columns
        content = []
        if tag:
            start, end = [int(i) for i in tag.split("-")]
        else:
            start, end = 0, df.shape[0]
        for line in range(start - 1, end):
            info = dict()
            info['INDEX'] = line + 1
            except_info = dict()
            for i, column in enumerate(columns):
                if column == 'text':
                    info['INPUT'] = df.loc[line, column]
                else:
                    except_info[column] = df.loc[line, column]
            info['EXPECT'] = except_info
            content.append(info)
        return content

    def __read_case(self, tag=None):
        start, end = check_line_filter(tag=tag)
        coop_list = []
        dialog = False
        with open(self.case_path, 'r') as file:
            lines = file.readlines()[start - 1:end]
        coop = []
        length = len(lines)
        for i in range(length - 1, -1, -1):
            data = lines[i].strip()
            if self.case_header.caseParam.value:
                data = data.replace(self.case_header.caseParam.name, self.case_header.caseParam.value)
            if data.isspace() or data.startswith("#") or data.startswith("//") or data.startswith("@") or len(data) == 0:
                continue
            if data.startswith("*") and ("dialog:start" not in data) and ("dialog:end" not in data):
                if not dialog:
                    coop.append((i + start, data))
                    coop_list.append(copy.deepcopy(coop))
                    coop.clear()
                else:
                    coop.append((i + start, data))
            elif data.startswith("*") and ("dialog:start" in data or "dialog:end" in data):
                if "dialog:start" in data:
                    coop.append((i+start, data))
                    coop_list.append(copy.deepcopy(coop))
                    coop.clear()
                    dialog = False
                elif "dialog:end" in data:
                    coop.append((i+start, data))
                    dialog = True
            else:
                coop.append((i + start, data))
        if len(coop) > 0:
            raise Exception(f"解析Case: {self.case_path} 失败, 请检查. start:{start}, end:{end}")
        elif len(coop_list) == 0:
            raise Exception(f"解析Case: {self.case_path} 失败, case_tag_list: {coop_list}. start:{start}, end:{end}")

        tmp_dict = {"INDEX": None, "INPUT": None, "PARAM": None, "EXPECTS": []}

        for case in coop_list:
            index_start, _ = case[-1]
            index_end, _ = case[0]
            expect_list = []
            for _, data in case:
                re_list = re.split(r'\t+', data)
                split_list = [item for item in re_list if item]
                line_data = [word.strip() for word in split_list]
                # 规定Case的标志
                if data.startswith("*"):
                    case_dict = copy.deepcopy(tmp_dict)
                    case_dict["INDEX"] = f"{index_start}-{index_end}"
                    case_dict["INPUT"] = line_data.pop(0)[1:]
                    case_dict["PARAM"] = line_data.pop(-1)
                    while len(line_data) > 0:
                        expect_list.append(line_data.pop(0))
                    for i in range(len(expect_list) - 1, -1, -1):
                        expect_items = {}
                        channel, msg_type, data, voiceRegion = self.__analyze_expected_meta(expect_list[i])
                        expect_items["channel"] = channel
                        expect_items["msgType"] = typeMapple[msg_type]
                        expect_items["expects"] = data
                        expect_items["voiceRegion"] = voiceRegion
                        case_dict["EXPECTS"].append(expect_items)

                    self.caseList.append(case_dict)
                    expect_list.clear()
                else:
                    while len(line_data) > 0:
                        expect_list.append(line_data.pop(0))

        return self.caseList[::-1]

    def __analyze_expected_meta(self, expects):
        channelId = self.case_header.channel.value
        msgType = self.case_header.msgType.value
        voiceRegion = [float('nan'), float('inf')]

        pattern = re.compile(r'^\[(.*?)\](.*)$')
        matchedContents = []
        datas = expects
        while True:
            match = pattern.match(datas)
            if match:
                # 解析channelId和msgType
                matchedContents.append(match.group(1))
                remaining_str = match.group(2)
                datas = remaining_str
            else:
                break

        # 如果找到匹配项
        try:
            for item in matchedContents:
                if not item:
                    raise Exception(f"解析Case失败: {expects}")
                if item.isdigit():
                    channelId = item
                else:
                    if item in typeMapple.keys():
                        msgType = item
                    else:
                        raise Exception(f"解析Case: {self.case_path} 失败: {expects}, 未知的断言类型: {item}")
        except Exception as e:
            raise e

        if not channelId or not msgType:
            raise Exception(f"解析Case: {self.case_path} 失败: {expects}, 未知的Channel或断言类型: {channelId}, {msgType}")

        pattern = r';voiceRegion:\[(.*?)\]'
        match = re.search(pattern, datas)
        if match:
            _region = match.group(1).split(",")
            start, end = round(float(_region[0]), 2), round(float(_region[1]), 2)
            voiceRegion = [start, end]
            datas = datas.split(";voiceRegion:")[0]

        return channelId, msgType, datas, voiceRegion
